﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Security.Cryptography;
using System.Net.Json;

public class Utility
{
	static DateTime BaseDateTime = new DateTime(1970, 1, 1, 0, 0, 0);

	public static String RenderJson(object obj)
	{
		StringBuilder builder = new StringBuilder();
		RenderJson(builder, obj);
		return builder.ToString();
	}

	public static void RenderJson(StringBuilder builder, object obj)
	{
		if (obj is IRenderJson)
		{
			(obj as IRenderJson).RenderJson(builder);
		}
		else if (obj is Exception)
		{
			builder.AppendFormat("{{\"__DataType\":\"Exception\",\"__Value\":{{\"Name\":\"{0}\",\"Message\":\"{1}\"}}}}", obj.GetType().Name, Utility.TransferCharJavascript((obj as Exception).Message));
		}
		else if (obj.GetType() == typeof(DateTime))
		{
			DateTime val = (DateTime)obj;
			RenderHashJson(
				builder,
				"__DataType", "Date",
				"__Value", (val - BaseDateTime).TotalMilliseconds
			);
		}
		else if (obj is IDictionary)
		{
			int count = 0;
			builder.Append("{");
			foreach (DictionaryEntry ent in (obj as IDictionary))
			{
				if (count > 0) builder.Append(",");
				builder.AppendFormat("\"{0}\":", Utility.TransferCharJavascript(ent.Key.ToString()));
				RenderJson(builder, ent.Value);
				count++;
			}
			builder.Append("}");
		}
		else if (obj is IList)
		{
			IList list = obj as IList;
			builder.Append("[");
			for (int i = 0; i < list.Count; i++)
			{
				if (i > 0) builder.Append(",");
				RenderJson(builder, list[i]);

			}
			builder.Append("]");
		}
		else if (obj is ICollection)
		{
			ICollection list = obj as ICollection;
			builder.Append("[");
			int count = 0;
			foreach (object val in list)
			{
				if (count > 0) builder.Append(",");
				RenderJson(builder, val);
				count++;
			}
			builder.Append("]");
		}
		else if (obj is DataRow)
		{
			DataRow row = obj as DataRow;
			builder.Append("{");

			int count = 0;
			foreach (DataColumn column in row.Table.Columns)
			{
				if (count > 0) builder.Append(",");
				builder.AppendFormat("\"{0}\":", column.ColumnName);
				RenderJson(builder, row[column.ColumnName]);
				count++;
			}

			builder.Append("}");
		}
		else if (obj is UInt16 || obj is UInt32 || obj is UInt64 || obj is Int16 || obj is Int32 || obj is Int64 || obj is Double || obj is Decimal || obj is long)
		{
			builder.Append(obj.ToString());
		}
		else if (obj is System.Drawing.Rectangle)
		{
			System.Drawing.Rectangle rect = (System.Drawing.Rectangle)obj;

			RenderHashJson(
				builder,
				"Left", rect.Left,
				"Top", rect.Top,
				"Width", rect.Width,
				"Height", rect.Height
			);
		}
		else if (obj is bool)
		{
			builder.Append((bool)obj ? "true" : "false");
		}
		else
		{
			builder.Append("\"");
			builder.Append(TransferCharJavascript(obj.ToString()));
			builder.Append("\"");
		}
	}

	public static String RenderHashJson(params object[] ps)
	{
		StringBuilder builder = new StringBuilder();
		builder.Append("{");
		for (int i = 0; i < ps.Length; i += 2)
		{
			if (i > 0) builder.Append(",");
			builder.AppendFormat("\"{0}\":", ps[i].ToString());
			RenderJson(builder, ps[i + 1]);
		}
		builder.Append("}");
		return builder.ToString();
	}

	public static void RenderHashJson(StringBuilder builder, params object[] ps)
	{
		builder.Append("{");
		for (int i = 0; i < ps.Length; i += 2)
		{
			if (i > 0) builder.Append(",");
			builder.AppendFormat("\"{0}\":", ps[i].ToString());
			RenderJson(builder, ps[i + 1]);
		}
		builder.Append("}");
	}

	public static string TransferCharJavascript(string s)
	{
		StringBuilder ret = new StringBuilder();
		foreach (char c in s)
		{
			switch (c)
			{
			case '\r':
			case '\t':
			case '\n':
			case '\f':
			case '\v':
			case '\"':
			case '\\':
			case '\'':
			case '<':
			case '>':
			case '\0':
				ret.AppendFormat("\\u{0:X4}", (int)c);
				break;
			default:
				ret.Append(c);
				break;
			}
		}
		return ret.ToString();
	}

	public static string TransferCharForXML(string s)
	{
		StringBuilder ret = new StringBuilder();
		foreach (char c in s)
		{
			switch (c)
			{
			case '\r':
			case '\t':
			case '\n':
			case '\f':
			case '\v':
			case '\"':
			case '\\':
			case '\'':
			case '<':
			case '>':
				ret.AppendFormat("&#{0};", (int)c);
				break;
			default:
				ret.Append(c);
				break;
			}
		}
		return ret.ToString();
	}

	public static string Decode(string s)
	{
		Regex r = new Regex("\\\\u[0-9a-fA-F]{4}|\\\\x[0-9a-fA-F]{2}");
		MatchEvaluator eval = new MatchEvaluator(ReplaceChar);
		return r.Replace(s, eval);
	}

	public static string ReplaceChar(Match match)
	{
		ushort ascii;
		if (match.Length == 4)
		{
			ascii = ushort.Parse(match.Value.Substring(2, 2), NumberStyles.HexNumber);
		}
		else
		{
			ascii = ushort.Parse(match.Value.Substring(2, 4), NumberStyles.HexNumber);
		}
		char c = Convert.ToChar(ascii);
		return c.ToString();
	}

	public static string MD5(string str)
	{
		MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
		byte[] data = md5.ComputeHash(UTF8Encoding.Default.GetBytes(str));
		StringBuilder sBuilder = new StringBuilder();
		for (int i = 0; i < data.Length; i++)
		{
			sBuilder.Append(data[i].ToString("X2"));
		}
		return sBuilder.ToString();
	}

	public static Object ParseJson(string jsonText)
	{
		if (!string.IsNullOrEmpty(jsonText))
		{
			JsonTextParser parser = new JsonTextParser();
			JsonObject obj = parser.Parse(jsonText);
			return ParseJson(obj);
		}
		else
		{
			return null;
		}
	}

	private static Object ParseJson(JsonObject jsonObject)
	{
		Type type = jsonObject.GetType();
		if (type == typeof(JsonObjectCollection))
		{
			Hashtable val = new Hashtable();
			foreach (JsonObject subObj in (jsonObject as JsonObjectCollection))
			{
				val.Add(subObj.Name, ParseJson(subObj));
			}
			if (val.ContainsKey("__DataType"))
			{
				if (val["__DataType"] as string == "Date")
				{
					return BaseDateTime.AddMilliseconds((Double)val["__Value"]);
				}
				else
				{
					return val;
				}
			}
			else
			{
				return val;
			}
		}
		else if (type == typeof(JsonArrayCollection))
		{
			List<object> val = new List<object>();
			foreach (JsonObject subObj in (jsonObject as JsonArrayCollection))
			{
				val.Add(ParseJson(subObj));
			}
			return val.ToArray();
		}
		else if (type == typeof(JsonBooleanValue))
		{
			return jsonObject.GetValue();
		}
		else if (type == typeof(JsonStringValue))
		{
			return jsonObject.GetValue();
		}
		else if (type == typeof(JsonNumericValue))
		{
			return jsonObject.GetValue();
		}
		else
			return null;
	}
}

public interface IRenderJson
{
	void RenderJson(StringBuilder builder);
}

public class JsonText : IRenderJson
{
	static JsonText m_EmptyObject = new JsonText("{}");

	static public JsonText EmptyObject
	{
		get { return m_EmptyObject; }
	}

	static JsonText m_EmptyArray = new JsonText("[]");

	static public JsonText EmptyArray
	{
		get { return m_EmptyArray; }
	}

	String m_Value;

	public JsonText(String value)
	{
		m_Value = value;
	}

	void IRenderJson.RenderJson(StringBuilder builder)
	{
		builder.Append(m_Value);
	}
}